let ENVIRONMENT = "production";

const AZURE_DEV_BASE_API_URL = "https://nuked.azurewebsites.net/api/";
const AZURE_PRODUCTION_BASE_API_URL = "https://nukedprod.azurewebsites.net/api/";
const LOCAL_BASE_API_URL = "http://localhost:5097/api/";

const API_KEY = "ed99f270-1cab-3ade-822b-81c08e30d57b";
const API_KEY_PARAMETER = "?api_key=" + API_KEY;

let BASE_API_URL = "";

let URLS = {};

const SYSTEM_ID = "PSL";
const JSON_CONTENT_TYPE = "application/json";
const JSON_BODY_HEADERS = {
	"Content-Type": JSON_CONTENT_TYPE
};

export function setNuclearApiEnvironment(environment) {
	ENVIRONMENT = environment;
	if (environment === "development") {
		BASE_API_URL = AZURE_DEV_BASE_API_URL;
		setUrls();
	} else if (environment === "production") {
		BASE_API_URL = AZURE_PRODUCTION_BASE_API_URL;
		setUrls();
	} else if (environment === "local") {
		BASE_API_URL = LOCAL_BASE_API_URL;
		setUrls();
	} else {
		console.log("Invalid environment " + environment);
	}
}

setNuclearApiEnvironment(ENVIRONMENT);

function setUrls() {
	console.log("Setting up urls");

	URLS.CONSUME_CODE_API_URL = BASE_API_URL + "consume_code";
	URLS.CONSUME_CODE_REQUEST_URL = URLS.CONSUME_CODE_API_URL + API_KEY_PARAMETER;

	URLS.MERCHANT_API_URL = BASE_API_URL + "merchant/";
	URLS.MERCHANT_LOGIN_REQUEST_URL = URLS.MERCHANT_API_URL + "login" + API_KEY_PARAMETER;
}

export function makeRequest(url, method, headers, data) {
	var jsonBody = data === undefined || data === null ? null : JSON.stringify(data);

	console.log("The " + method + " request url is:");
	console.log(url);

	if (hasValue(jsonBody)) {
		console.log("The request json body is:");
		console.log(jsonBody);
	}

	var isNonUniEnvironment = typeof(uni) === "undefined" ||
		typeof(uni?.request) === "undefined";

	return new Promise((resolve, reject) => {
		if (isNonUniEnvironment) {
			var requestPromise = fetch(url, {
				method: method || "GET",
				headers: headers,
				body: jsonBody
			});

			handleResponse(requestPromise, resolve, reject);

			return;
		}

		data = data || {};
		uni.request({
			url: url,
			method: method || "GET",
			header: headers,
			data: data,
			success: (res) => {
				handleJsonResponse(res.data, resolve, reject);
			},
			fail: (message) => {
				handleJsonResponse(message, "", reject);
			}
		});
	});
}

export function padToDigits(num, numOfDigits = 2) {
	return num.toString().padStart(numOfDigits, '0');
}

export function formatDate(date = new Date()) {
	return [
		date.getFullYear(),
		padToDigits(date.getMonth() + 1),
		padToDigits(date.getDate()),
	].join('-');
}

export function formatDateTimeToMinutes(date = new Date()) {
	return formatDate(date) + ' ' + [
		padToDigits(date.getHours()),
		padToDigits(date.getMinutes())
	].join(':');
}

async function handleResponse(requestPromise, resolve, reject) {
	try {
		var response = await requestPromise;
		if (!response.ok) {
			var text = await response.text();
			handleFailResponse(text, "status - " + response.status, reject);
			return;
		}
		var text = await response.text();
		try {
			var json = JSON.parse(text);
			handleJsonResponse(json, resolve, reject);
		} catch (error) {
			handleFailResponse(text, "", reject);
		}
	} catch (error) {
		console.log(error);
		handleFailResponse(error.message, error.cause, reject);
	}
}

function isFailJsonResponse(response) {
	return typeof(response.status) === "number";
}

function handleJsonResponse(jsonResponse, resolve, reject) {
	if (isFailJsonResponse(jsonResponse)) {
		handleFailJsonResponse(jsonResponse, reject);
		return;
	}

	var error = jsonResponse.error;
	var data = jsonResponse.data;
	if (error.code === 200) {
		resolve(data);
	} else {
		reject(error);
	}
}

function handleFailJsonResponse(jsonResponse, reject) {
	var message = jsonResponse.message || jsonResponse.title;
	var errors = jsonResponse.errors;
	if (hasValue(errors)) {
		for (const key in errors) {
			if (errors.hasOwnProperty(key)) {
				var errorValue = errors[key];
				message += " " + key + ": ";
				if (Array.isArray(errorValue)) {
					errorValue.forEach(errorItem => {
						message += errorItem + " ";
					})
				} else {
					message += errorValue + "";
				}
			}
		}

		message = message.trim();
	}

	var error = {
		code: jsonResponse.status,
		message,
		user_message: "服务器发生未知错误, 请稍候再试"
	};
	reject(error);
}

function handleFailResponse(message, cause, reject) {
	if (cause === undefined || cause === null || isNaN(cause)) {
		cause = "";
	} else {
		cause = ". " + cause;
	}
	reject({
		code: 500,
		message: "The API service is unaccessible: " + (message || "unknown error") + cause,
		user_message: "后台服务无法访问: " + (message || "未知错误") + cause
	});
}

export function hasValue(data) {
	return data !== undefined && data !== null;
}

export function addQuery(url, parameterName, parameterValue) {
	if (!hasValue(parameterValue)) {
		return url;
	}

	if (parameterValue === true) {
		parameterValue = "true";
	}
	if (parameterValue === false) {
		parameterValue = "false";
	}
	if (url.includes("?"))
		url += "&";
	else
		url += "?";

	if (Array.isArray(parameterValue)) {
		for (var i = 0; i < parameterValue.length; i++) {
			var value = parameterValue[i];
			url = addQuery(url, parameterName, value);
		}

		return url;
	}

	return url + parameterName + "=" + encodeURI(parameterValue);
}

export async function generateConsumeCode(
	merchantId,
	userId,
	productId,
	benefitsCardNo,
	districtId,
	prefix,
	validFrom,
	validTo,
	count
) {
	var data = {
		system_id: SYSTEM_ID,
		merchant_id: merchantId,
		user_id: userId,
		product_id: productId,
		benefits_card_no: benefitsCardNo,
		district_id: districtId,
		prefix: prefix,
		valid_from: validFrom,
		valid_to: validTo,
		count: count,
		save: true
	};

	return makeRequest(URLS.CONSUME_CODE_REQUEST_URL, "POST", JSON_BODY_HEADERS, data);
}

export async function useConsumeCode(
	merchantId,
	userId,
	productId,
	benefitsCardNo,
	code
) {
	var data = {
		system_id: SYSTEM_ID,
		merchant_id: merchantId,
		user_id: userId,
		product_id: productId,
		benefits_card_no: benefitsCardNo,
		consume_code: code
	};
	return makeRequest(URLS.CONSUME_CODE_REQUEST_URL, "PUT", JSON_BODY_HEADERS, data);
}

export async function getConsumeCodes(
	merchantId,
	productId,
	userId,
	benefitsCardNo,
	code,
	districtId,
	isUsed
) {
	var url = URLS.CONSUME_CODE_REQUEST_URL;
	url = addQuery(url, "system_id", SYSTEM_ID);
	url = addQuery(url, "merchant_id", merchantId);
	url = addQuery(url, "user_id", userId);
	url = addQuery(url, "benefits_card_no", benefitsCardNo);
	url = addQuery(url, "consume_code", code);
	url = addQuery(url, "product_id", productId);
	url = addQuery(url, "district_id", districtId);
	url = addQuery(url, "is_used", isUsed);
	console.log(url);
	return makeRequest(url, "GET");
}

export async function loginAsMerchant(
	userName, password
) {
	var data = {
		system_id: SYSTEM_ID,
		user_name: userName,
		password: password
	};

	return makeRequest(URLS.MERCHANT_LOGIN_REQUEST_URL, "POST", JSON_BODY_HEADERS, data);
}

export async function generateTenConsumeCodesAndUseFirstOne(merchantId) {
	merchantId = merchantId || "23978";
	let userId = "18823214892";
	let productId = "79378";
	let benefitsCardNo = "235218";
	let today = new Date();

	let validFrom = formatDate(today);
	let oneYearLater = new Date(today.getFullYear() + 1, today.getMonth(), today.getDate());
	let validTo = formatDate(oneYearLater);
	var generateResult = await generateConsumeCode(
		merchantId,
		userId,
		productId,
		benefitsCardNo,
		"CZH",
		"CZ",
		validFrom,
		validTo,
		10
	);

	let consumeCodes = generateResult.consume_codes;
	console.log("Generated " + consumeCodes.length + " consume codes:");
	console.log(consumeCodes);

	var consumeCode = consumeCodes[0];
	var useResult = await useConsumeCode(merchantId, userId, productId, benefitsCardNo, consumeCode);
	console.log(useResult);
	console.log("Successfully used consume code " + consumeCode);

	return {
		merchantId,
		productId,
		userId,
		benefitsCardNo,
		consumeCode
	};
}

export async function loginAsTestMerchant() {
	let userName = "18823214892";
	let password = "000000";
	var loginResult = await loginAsMerchant(
		userName,
		password
	);

	var merchantId = loginResult.merchant_id;
	var realName = loginResult.real_name;
	console.log("Logged in as " + userName + " with merchant id " + merchantId + " and real name " + realName);
	return {
		merchantId,
		realName
	};
}

// try {
//     var loginResult = await loginAsTestMerchant();
//     var usedConsumeCodeInfo = await generateTenConsumeCodesAndUseFirstOne(loginResult.merchantId);
//     console.log("The used code info is:");
//     console.log(usedConsumeCodeInfo);

//     var consumeCodeDetails = await getConsumeCodes(
//         usedConsumeCodeInfo.merchantId,
//         usedConsumeCodeInfo.productId,
//         usedConsumeCodeInfo.userId,
//         usedConsumeCodeInfo.benefitsCardNo,
//         usedConsumeCodeInfo.consumeCode
//     );

//     console.log("The consume code is: ");
//     console.log(consumeCodeDetails);
// }
// catch (e) {
//     console.log(e);
// }